using System;
using System.Collections.Generic;
using System.Text;

namespace GoogleCalendarReminder
{
    static class Program
    {
        #region Private Data Members

        private static gui.AlertForm _alertForm;
        private static System.Windows.Forms.NotifyIcon _notifyIcon;
        private static EventService _eventService;
        private static Google.GData.Calendar.CalendarService _calendarService;
        private static bool _showConnectionBalloon = true;
        private static System.Timers.Timer _checkInternetConnectionTimer;

        private static System.Threading.Mutex _singleApp =
            new System.Threading.Mutex(false, Properties.Settings.Default.AppName);

        #endregion

        #region Private Functions

        /// <summary>
        /// Checks the internet connection every 5 minutes.
        /// </summary>
        private static void _checkInternetConnectionTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            _eventService.Start();

            if (_eventService.State == EventServiceState.Started)
            {
                _showConnectionBalloon = true;
                _checkInternetConnectionTimer.Stop();
            }
        }

        /// <summary>
        /// Handles connection errors the event service might throw.
        /// </summary>
        private static void _eventService_ExceptionOccured(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
        {
            if (_showConnectionBalloon && e.Error != null)
            {
                _notifyIcon.ShowBalloonTip(
                    7 * 1000,
                    "Google Calendar Reminder",
                    "A connection couldn't be established with the Google Calendar service. Check your internet connection.",
                    System.Windows.Forms.ToolTipIcon.Error);

                _showConnectionBalloon = false;
                _checkInternetConnectionTimer.Start();
            }
        }

        /// <summary>
        /// Displays the form if events exist.
        /// </summary>
        private static void _notifyIcon_DoubleClick(object sender, EventArgs e)
        {
            if (_alertForm.Subscriber.Events.Count > 0)
            {
                _alertForm.PlaySoundOnShown = false;
                _alertForm.Show();
                _alertForm.PlaySoundOnShown = true;
            }
        }

        /// <summary>
        /// This removes the icon from the system tray without the user having to hover
        /// the mouse over it when the application exits.
        /// </summary>
        private static void Application_ApplicationExit(object sender, EventArgs e)
        {
            _notifyIcon.Visible = false;
        }

        /// <summary>
        /// Attempts to change the credentials.
        /// </summary>
        private static void changeCredentials_Click(object sender, EventArgs e)
        {
            GoogleAccountCredentials credentials = getCredentials();

            if (credentials != null)
            {
                _eventService.Stop();
                _eventService.Service.setUserCredentials(credentials.Username, credentials.Password);
                _eventService.Start();
            }
        }

        /// <summary>
        /// Prompts the user for automatic startup on first run of the program.
        /// </summary>
        private static void checkAutoStartup()
        {
            if (Properties.Settings.Default.FirstStartup)
            {
                System.Windows.Forms.DialogResult result =
                    System.Windows.Forms.MessageBox.Show(
                    "Would you like Google Calendar Reminder to startup with Windows?",
                    "Automatic Startup",
                    System.Windows.Forms.MessageBoxButtons.YesNo,
                    System.Windows.Forms.MessageBoxIcon.Question,
                    System.Windows.Forms.MessageBoxDefaultButton.Button1);

                if (result == System.Windows.Forms.DialogResult.Yes)
                {
                    StartupManager.StartWithWindows = true;
                }

                Properties.Settings.Default.FirstStartup = false;
                Properties.Settings.Default.Save();
            }
        }

        /// <summary>
        /// Creates the notify icon and context menu.
        /// </summary>
        private static void createNotifyIcon()
        {
            _notifyIcon = new System.Windows.Forms.NotifyIcon();
            _notifyIcon.Icon = Properties.Resources.Calendar;
            _notifyIcon.Text = "Google Calendar Reminder";
            _notifyIcon.Visible = true;

            System.Windows.Forms.ContextMenuStrip notifyStrip =
                new System.Windows.Forms.ContextMenuStrip();

            _notifyIcon.DoubleClick += new EventHandler(_notifyIcon_DoubleClick);

            System.Windows.Forms.ToolStripMenuItem updateReminders =
                new System.Windows.Forms.ToolStripMenuItem("Update reminders", Properties.Resources.Refresh);
            updateReminders.Click += new EventHandler(updateReminders_Click);

            System.Windows.Forms.ToolStripMenuItem changeCredentials =
                new System.Windows.Forms.ToolStripMenuItem("Change credentials...", Properties.Resources.EditInformation);
            changeCredentials.Click += new EventHandler(changeCredentials_Click);

            System.Windows.Forms.ToolStripMenuItem startupWithWindows =
                new System.Windows.Forms.ToolStripMenuItem("Startup with Windows");
            startupWithWindows.CheckOnClick = true;
            startupWithWindows.Checked = StartupManager.StartWithWindows;
            startupWithWindows.CheckedChanged += new EventHandler(startupWithWindows_CheckedChanged);

            System.Windows.Forms.ToolStripSeparator seperatorOne =
                new System.Windows.Forms.ToolStripSeparator();

            System.Windows.Forms.ToolStripMenuItem validReminders =
                new System.Windows.Forms.ToolStripMenuItem("Valid reminders");

            foreach (System.Reflection.FieldInfo fInfo in typeof(ReminderMethods).GetFields())
            {
                if (fInfo.IsStatic)
                {
                    System.Windows.Forms.ToolStripMenuItem newItem =
                        new System.Windows.Forms.ToolStripMenuItem(fInfo.Name);
                    newItem.Tag = fInfo.GetValue(fInfo);
                    newItem.CheckOnClick = true;
                    newItem.Checked = Properties.Settings.Default.ValidReminders.Contains((string)newItem.Tag);
                    newItem.CheckedChanged += new EventHandler(newItem_CheckedChanged);

                    validReminders.DropDownItems.Add(newItem);
                }
            }

            System.Windows.Forms.ToolStripSeparator seperatorTwo =
                new System.Windows.Forms.ToolStripSeparator();

            System.Windows.Forms.ToolStripMenuItem quitProgram =
                new System.Windows.Forms.ToolStripMenuItem("Quit");
            quitProgram.Click += new EventHandler(quitProgram_Click);

            notifyStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
                updateReminders,
                changeCredentials,
                startupWithWindows,
                seperatorOne,
                validReminders,
                seperatorTwo,
                quitProgram });

            _notifyIcon.ContextMenuStrip = notifyStrip;
        }

        private static void newItem_CheckedChanged(object sender, EventArgs e)
        {
            System.Windows.Forms.ToolStripMenuItem menuItem =
                sender as System.Windows.Forms.ToolStripMenuItem;

            if (menuItem != null)
            {
                if (menuItem.Checked)
                {
                    Properties.Settings.Default.ValidReminders.Add((string)menuItem.Tag);
                }
                else
                {
                    Properties.Settings.Default.ValidReminders.Remove((string)menuItem.Tag);
                }

                Properties.Settings.Default.Save();
            }
        }

        /// <summary>
        /// Displays the credential dialog box.
        /// </summary>
        /// <returns>Google account credentials if valid; null otherwise.</returns>
        private static GoogleAccountCredentials getCredentials()
        {
            bool isValid = false;
            GoogleAccountCredentials creds = null;
            gui.CredentialForm credForm = new gui.CredentialForm();

            while (!isValid)
            {
                if (credForm.ShowDialog(_alertForm) == System.Windows.Forms.DialogResult.OK)
                {
                    creds = new GoogleAccountCredentials(credForm.Username, credForm.Password);

                    try
                    {
                        CredentialManager.SaveCredentials(creds);
                        isValid = true;
                    }
                    catch (Google.GData.Client.InvalidCredentialsException) { }
                }
                else
                {
                    return null;
                }
            }

            return creds;
        }

        /// <summary>
        /// Sets the startup with Windows preference.
        /// </summary>
        private static void startupWithWindows_CheckedChanged(object sender, EventArgs e)
        {
            StartupManager.StartWithWindows = ((System.Windows.Forms.ToolStripMenuItem)(sender)).Checked;
        }

        /// <summary>
        /// Exits the application.
        /// </summary>
        private static void quitProgram_Click(object sender, EventArgs e)
        {
            System.Windows.Forms.Application.Exit();
        }

        /// <summary>
        /// Restarts the service.
        /// </summary>
        private static void updateReminders_Click(object sender, EventArgs e)
        {
            _showConnectionBalloon = true;
            _eventService.Stop();
            _eventService.Start();
        }

        #endregion

        #region Set System Time Data Members

        [System.Runtime.InteropServices.StructLayout(
           System.Runtime.InteropServices.LayoutKind.Sequential)]
        public struct SYSTEMTIME
        {
            public short wYear;
            public short wMonth;
            public short wDayOfWeek;
            public short wDay;
            public short wHour;
            public short wMinute;
            public short wSecond;
            public short wMilliseconds;
        }

        [System.Runtime.InteropServices.DllImport("kernel32.dll", SetLastError = true)]
        public static extern bool SetSystemTime([System.Runtime.InteropServices.In] ref SYSTEMTIME st);

        private static void setTime()
        {
            SYSTEMTIME st = new SYSTEMTIME();
            st.wYear = 2008;
            st.wMonth = 5;
            st.wDay = 5;
            st.wHour = 9 + 4;
            st.wMinute = 0;
            st.wSecond = 0;

            SetSystemTime(ref st);
        }

        #endregion

        [STAThread]
        static void Main()
        {
            if (!_singleApp.WaitOne(TimeSpan.FromSeconds(5), false)) return;

            System.Windows.Forms.Application.EnableVisualStyles();
            System.Windows.Forms.Application.SetCompatibleTextRenderingDefault(false);

            //setTime();

            checkAutoStartup();

            _checkInternetConnectionTimer = new System.Timers.Timer(5 * 60 * 1000);
            _checkInternetConnectionTimer.AutoReset = true;
            _checkInternetConnectionTimer.Elapsed += new System.Timers.ElapsedEventHandler(_checkInternetConnectionTimer_Elapsed);

            _eventService = new EventService();
            _calendarService = new Google.GData.Calendar.CalendarService(Properties.Settings.Default.AppName);
            _eventService.Service = _calendarService;
            _alertForm = new GoogleCalendarReminder.gui.AlertForm(new EventServiceSubscriber(_eventService));

            createNotifyIcon();

            try
            {
                GoogleAccountCredentials credentials = CredentialManager.RetrieveCredentials();
                _calendarService.setUserCredentials(credentials.Username, credentials.Password);
            }
            catch (Google.GData.Client.InvalidCredentialsException)
            {
                GoogleAccountCredentials credentials = getCredentials();

                if (credentials == null)
                {
                    Application_ApplicationExit(null, EventArgs.Empty);
                    return;
                }

                _calendarService.setUserCredentials(credentials.Username, credentials.Password);
            }

            _eventService.ExceptionOccured += new EventHandler<System.ComponentModel.AsyncCompletedEventArgs>(_eventService_ExceptionOccured);
            _eventService.Start();

            System.Windows.Forms.Application.ApplicationExit += new EventHandler(Application_ApplicationExit);
            System.Windows.Forms.Application.Run();
        }
    }
}
